package jsonmarshal

import (
	"fmt"
	"reflect"
	"strings"
	"errors"
)

// ptrMarshal 将 ptr 类型转成 JSON 编码，输出跟指针指向的对象的输出相同
func ptrMarshal(v interface{}) string {
	value := reflect.ValueOf(v)
	return Marshal(value.Elem().Interface())
}

// basicMarshal 将基本类型（bool, int, float, char）直接打印原值实现序列化
func basicMarshal(v interface{}) string {
	value := reflect.ValueOf(v)
	str := fmt.Sprintf("%v", value.Interface())
	return str
} 

// stringMarshal 将 string 类型转成 JSON 编码
func stringMarshal(v interface{}) string {
	var vStr = fmt.Sprintf("%v", v)
	// “<”,“>”和“＆”会转义为“\u003c”,“\u003e”和“\u0026”，防止某些浏览器将 JSON 输出误解为 HTML。
	s := []rune(vStr)
	str1 := "\\u003c"
	str2 := "\\u003e"
	str3 := "\\u0026"
	res := ""

	for _, r := range s {
		if rune(r) == rune('<') {
			res = res + str1
		} else if rune(r) == rune('>') {
			res = res + str2
		} else if rune(r) == rune('&') {
			res = res + str3
		} else {
			res = res + string(r)
		}
	}
	res = "\"" + res + "\""
	return res
}

// arrayMarshal 将定长 array 和不定长 slice 类型转成 JSON 编码
func arrayMarshal(v interface{}) string {
	value := reflect.ValueOf(v)
	res := ""
	for i := 0; i < value.Len(); i++ {
		index := value.Index(i)
		res += Marshal(index.Interface())
		if i != value.Len()-1  {
			res += ","
		}
	}
	return "[" + res + "]"
}

// mapMarshal 将 map 类型转成 JSON 编码
func mapMarshal(v interface{}) string {
	value := reflect.ValueOf(v)
	keys := value.MapKeys()
	res := ""

	for i := 0; i < len(keys); i++ {
		key := keys[i]
		v := value.MapIndex(key)
		res += Marshal(key.Interface()) + ":" + Marshal(v.Interface())
		if i != value.Len()-1  {
			res += ","
		}
	}
	return "{" + res + "}"
}

// structMarshal 将 struct 类型转成 JSON 编码
func structMarshal(v interface{}) string {
	vType := reflect.TypeOf(v)
	value := reflect.ValueOf(v)
	res := ""
	for i := 0; i < vType.NumField(); i++ {
		if i > 0 {
			res += ","
		}
		field := vType.Field(i)
		v := value.Field(i)
		tag := field.Tag
		json, ok := tag.Lookup("mytag")

		// 分类处理 tag 值
		key := field.Name
		if !ok {
			// 不处理
		}
		if json == "-" {
			// 忽略
			continue
		}
		if json == "-," {
			// key 为 "-"
			key = "-"
		}

		sep := ","
		temp := strings.Split(json, sep)

		if len(temp) != 2 {
			// key 为 json
			key = json
		} else if temp[1] == "omitempty" {
			     if v.Interface() == 0 || v.Interface() == "" || v.Interface() == 0.0 {
				    continue
			     }  
			     if temp[0] != "" {
					key = temp[0]
			     } 
		}

		key = "\"" + key + "\""
		res += key + ":" + Marshal(v.Interface())
	}
	return "{" + res + "}"
}

// 调用 reflect 得到任意类型对象的类型和值
// Marshal 调用各种类型解析方法，将接口 v 转换为 JSON 编码的字符串
func Marshal(v interface{}) string {
	vType := reflect.TypeOf(v)
	switch vType.Kind() {
	case reflect.Bool, 
	    reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint64,
        reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32,
        reflect.Float32, reflect.Float64:
		return basicMarshal(v)

	case reflect.String:
		return stringMarshal(v)

	case reflect.Ptr, reflect.Uintptr:
		return ptrMarshal(v)

	case reflect.Array, reflect.Slice:
		return arrayMarshal(v)

	case reflect.Map:
		return mapMarshal(v)

	case reflect.Struct:
		return structMarshal(v)

	default:
		return basicMarshal(v)
	}
}

//JsonMarshal 调用 Marshal 函数将接口 v 的具体值转换为 JSON 字符串，如果成功则将字符串转换成 []byte 字符流并返回
//如果出现不能转换为 JSON 编码的将返回 “类型非法” 错误
func JsonMarshal(v interface{}) ([]byte, error) {
	jsonStr := Marshal(v)
	if jsonStr  == "" {
		return []byte("null"), errors.New("Error: Illegal Type!")
	}
	return []byte(jsonStr), nil
}
